"""
# -*- coding: utf-8 -*-
# @Time    : 2023/6/14 9:55
# @Author  : 王摇摆
# @FileName: FeatureUnion.py
# @Software: PyCharm
# @Blog    ：https://blog.csdn.net/weixin_44943389?type=blog
"""
from sklearn.pipeline import Pipeline
from sklearn.pipeline import FeatureUnion
from sklearn.impute import SimpleImputer
from sklearn.preprocessing import MinMaxScaler
from sklearn.preprocessing import OneHotEncoder
import numpy as np
import pandas as  pd
from sklearn.base import BaseEstimator, TransformerMixin

d = {'IQ': ['high', 'avg', 'avg', 'low', 'high', 'avg', 'high', 'high', None],
     'temper': ['good', None, 'good', 'bad', 'bad', 'bad', 'bad', None, 'bad'],
     'income': [50, 40, 30, 5, 7, 10, 9, np.NaN, 12],
     'height': [1.68, 1.83, 1.77, np.NaN, 1.9, 1.65, 1.88, np.NaN, 1.75]}
X = pd.DataFrame(d)
print('1. 数据集加载成功')


# 获取数据列的类
class DataFrameSelector(BaseEstimator, TransformerMixin):
    def __init__(self, attribute_names):
        self.attribute_names = attribute_names

    def fit(self, X, y=None):
        return self

    def transform(self, X):
        return X[self.attribute_names].values


# 开始创建流水线
categorical_features = ['IQ', 'temper']
numeric_features = ['income', 'height']

categorical_pipe = Pipeline([
    ('select', DataFrameSelector(categorical_features)),
    ('impute', SimpleImputer(missing_values=None, strategy='most_frequent')),
    ('one_hot_encode', OneHotEncoder(sparse=False))])  # 串联流水线是由多个度机器来组成，元祖的形式

numeric_pipe = Pipeline([
    ('select', DataFrameSelector(numeric_features)),
    ('impute', SimpleImputer(missing_values=np.nan, strategy='mean')),
    ('normalize', MinMaxScaler())])

full_pipe = FeatureUnion(transformer_list=[
    ('numeric_pipe', numeric_pipe),
    ('categorical_pipe', categorical_pipe)])  # 将上述创建的两个流水线并联起来
print('2. 并联流水线创建完毕')

'''
对类别型变量：获取数据 → 中位数填充 → 独热编码
对数值型变量：获取数据 → 均值填充 → 标准化
'''

# 开始数据清洗工作
X_proc = full_pipe.fit_transform(X)
print('3. 数据清洗工作已完成')

print('\n===============数据清洗前的数据所示=================')
print(X)  # 添加输出语句

print('\n===============数据清洗结果如下所示=================')
np.set_printoptions(precision=2, suppress=True)
feature_names = ['income', 'height', 'IQ_avg', 'IQ_high', 'IQ_low', 'temper_bad', 'temper_good']
# 打印表头
header = '序号 ' + ' '.join(f'{name:<9}' for name in feature_names)
print(header)

# 遍历输出结果
for i, row in enumerate(X_proc):
    row_data = ''
    for j, value in enumerate(row):
        if feature_names[j] in ['IQ_high', 'IQ_avg', 'IQ_low', 'temper_good', 'temper_bad']:
            row_data += f'{int(value):<9} '
        else:
            row_data += f'{value:<9.2f} '
    print(f'{i:<4} {row_data}')

'''
输出结果7列的含义解释:
根据您提供的代码，`X_proc` 是经过特征处理和组合后的输出结果，形状为 (9, 7)。每一列代表一个特征。

对于 `X` 数据集中的每一行，在特征处理和组合过程中，经过 `numeric_pipe` 和 `categorical_pipe` 的处理后，生成了 7 个新的特征。这些特征如下所示：

1. 数值型特征 'income' 经过均值填充和归一化处理后的结果。
2. 数值型特征 'height' 经过均值填充和归一化处理后的结果。
3. 类别型特征 'IQ' 经过最频繁值填充和独热编码处理后的结果：'high' 对应的列。
4. 类别型特征 'IQ' 经过最频繁值填充和独热编码处理后的结果：'avg' 对应的列。
5. 类别型特征 'IQ' 经过最频繁值填充和独热编码处理后的结果：'low' 对应的列。
6. 类别型特征 'temper' 经过最频繁值填充和独热编码处理后的结果：'good' 对应的列。
7. 类别型特征 'temper' 经过最频繁值填充和独热编码处理后的结果：'bad' 对应的列。

每一列的值代表相应特征在该样本上的取值。注意，由于使用了独热编码，每个类别特征都会被转换为多个二进制列，以表示不同的类别。

请注意，具体的特征列顺序可能会有所不同，取决于 `FeatureUnion` 中流水线的顺序以及类别型特征的编码顺序。

希望这样的解释对您有帮助。如果您有其他问题，请随时提问。
'''
